package zd.vrp.ais;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import zd.vrp.global.Route;
import zd.vrp.mop.MultiObjective;
import zd.vrp.mop.MultiObjectiveRank;
import zd.vrp.mop.RankComparator;
import zd.vrp.utils.TestUtils;

public class Fitness {
	private List population;
	private List<MultiObjective> multiObjectiveList = new ArrayList<MultiObjective>();
	
	private List<MultiObjectiveRank> morList = new ArrayList<MultiObjectiveRank>();
	private List<List> hierachy = new ArrayList<List>();
	
	//solution pareto rank
	private List paretoRank = new ArrayList();
	
	
	public Fitness(List population){
		this.population = population;
		calFitness(this.population);
		
		paretoRank();
	}
	
	/**
	 * naive fitness value calculation
	 * 
	 */
	private void calFitness(List population){
		/**
		 * we will have two objective, the first one is vehile number and second one is total length
		 * 
		 */
		//List<MultiObjective> multiObjectiveList = new ArrayList<MultiObjective>();
		for(int i=0;i<population.size();i++){
			List<Route> solution = (List<Route>) population.get(i);
			
			double vehicleNum = 0.0;
			double totalLength = TestUtils.getTotalLength(solution);
			
			for(int j=0;j<solution.size();j++){
				Route route = solution.get(j);
				if(route.getCityList().size()>2){
					vehicleNum = vehicleNum + 1;
				}
			}
			MultiObjective mo = new MultiObjective();
			List mList = new ArrayList();
			mList.add(vehicleNum);
			mList.add(totalLength);
			mo.setObjectives(mList);
			
			multiObjectiveList.add(mo);
		}
	}

	public List getPopulation() {
		return population;
	}

	public void setPopulation(List population) {
		this.population = population;
	}

	public List<MultiObjective> getMultiObjectiveList() {
		return multiObjectiveList;
	}

	public void setMultiObjectiveList(List<MultiObjective> multiObjectiveList) {
		this.multiObjectiveList = multiObjectiveList;
	}
	
	public List<MultiObjectiveRank> getMorList() {
		return morList;
	}

	public void setMorList(List<MultiObjectiveRank> morList) {
		this.morList = morList;
	}

	public List getParetoRank() {
		return paretoRank;
	}

	public void setParetoRank(List paretoRank) {
		this.paretoRank = paretoRank;
	}
	
	public List<List> getHierachy() {
		return hierachy;
	}

	public void setHierachy(List<List> hierachy) {
		this.hierachy = hierachy;
	}

	//rank all the multi objective
	private void paretoRank(){
		morList.clear();
		for(int i=0;i<this.multiObjectiveList.size();i++){
			MultiObjectiveRank mor = this.multiObjectiveList.get(i).getRank(this.multiObjectiveList);
			morList.add(mor);
			mor.setPosition(i);
		}
		
		Collections.sort(morList,new RankComparator());
		
		double currentTotal = morList.get(0).getTotal();
		List<MultiObjective> currentHierachy = new ArrayList<MultiObjective>();
		currentHierachy.add(multiObjectiveList.get(morList.get(0).getPosition()));
		for(int i=1;i<morList.size();i++){
			double tempTotal = morList.get(i).getTotal();
			if(tempTotal == currentTotal){
				currentHierachy.add(multiObjectiveList.get(morList.get(i).getPosition()));
				
			}else{
				hierachy.add(currentHierachy);
				currentHierachy = new ArrayList<MultiObjective>();
				currentHierachy.add(multiObjectiveList.get(morList.get(i).getPosition()));
				currentTotal = tempTotal;
			}
		}
		hierachy.add(currentHierachy);
	}
	
}
